package org.gdstash.character;

import org.gdstash.db.DBSkillTree;
import org.gdstash.file.GDReader;
import org.gdstash.file.GDWriter;
import org.gdstash.ui.character.GDCharMasteryImagePane;
import org.gdstash.util.FileVersionException;
import org.gdstash.util.GDMsgFormatter;

import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class GDCharSkillList {
    private static final int VERSION_5 = 5;
    private static final int VERSION_6 = 6;
    private static final int BLOCK = 8;
    private int version;
    private List<GDCharSkill> charSkills;
    private List<GDCharItemSkill> itemSkills;
    private int masteriesAllowed;
    private int skillReclamationPointsUsed;
    private int devotionReclamationPointsUsed;
    private List<GDCharSubSkill> subSkills;
    private boolean changed;

    public GDCharSkillList() {
        this.charSkills = new LinkedList<GDCharSkill>();
        this.itemSkills = new LinkedList<GDCharItemSkill>();
        this.subSkills = new LinkedList<GDCharSubSkill>();
    }

    public int getSkillReclaimPoints() {
        return this.skillReclamationPointsUsed;
    }

    public int getDevotionReclaimPoints() {
        return this.devotionReclamationPointsUsed;
    }

    public List<GDCharSkill> getMasteries() {
        final List<GDCharSkill> masteries = new LinkedList<GDCharSkill>();
        if (this.charSkills != null) {
            for (final GDCharSkill skill : this.charSkills) {
                if (skill.isMastery()) {
                    masteries.add(skill);
                }
            }
        }
        return masteries;
    }

    public List<GDCharSkill> getCharSkillList() {
        return this.charSkills;
    }

    public List<GDCharSkill> getSkillsByMastery(final String masteryID) {
        final List<GDCharSkill> list = new LinkedList<GDCharSkill>();
        if (this.charSkills != null) {
            for (final GDCharSkill skill : this.charSkills) {
                if (skill.getMasteryID() != null && skill.getMasteryID().equals(masteryID)) {
                    list.add(skill);
                }
            }
        }
        return list;
    }

    public List<GDCharSkill> getDevotions() {
        final List<GDCharSkill> devotions = new LinkedList<GDCharSkill>();
        if (this.charSkills != null) {
            for (final GDCharSkill skill : this.charSkills) {
                if (skill.isDevotion() && skill.getSkillLevel() > 0) {
                    devotions.add(skill);
                }
            }
        }
        return devotions;
    }

    public int getSkillMaxLevel(final String skillID) {
        int maxLevel = 0;
        if (this.charSkills != null) {
            for (final GDCharSkill skill : this.charSkills) {
                if (skill.getID().equals(skillID)) {
                    maxLevel = skill.getMaxLevel();
                    break;
                }
            }
        }
        return maxLevel;
    }

    public boolean hasChanged() {
        return this.changed;
    }

    public void setSkillReclaimPoints(final int skillReclamationPointsUsed) {
        this.skillReclamationPointsUsed = skillReclamationPointsUsed;
        this.changed = true;
    }

    public void setDevotionReclaimPoints(final int devotionReclamationPointsUsed) {
        this.devotionReclamationPointsUsed = devotionReclamationPointsUsed;
        this.changed = true;
    }

    public void setSkillLevel(final GDChar.SkillInfo[] infos) {
        if (infos == null) {
            return;
        }
        for (int i = 0; i < infos.length; ++i) {
            for (final GDCharSkill skill : this.charSkills) {
                if (skill.getID().equals(infos[i].id)) {
                    skill.setLevel(infos[i].points);
                    break;
                }
            }
        }
        this.changed = true;
    }

    public void setMasterySkills(final String masteryID, final List<GDCharMasteryImagePane.Skill> list) {
        if (list == null) {
            return;
        }
        if (list.isEmpty()) {
            return;
        }
        if (this.charSkills == null) {
            return;
        }
        final List<GDCharSkill> newList = new LinkedList<GDCharSkill>();
        for (final GDCharSkill skill : this.charSkills) {
            if (skill.getMasteryID() == null) {
                newList.add(skill);
            } else if (!skill.getMasteryID().equals(masteryID)) {
                newList.add(skill);
            } else {
                GDCharMasteryImagePane.Skill match = null;
                for (final GDCharMasteryImagePane.Skill mps : list) {
                    if (mps.skill.getSkillID().equals(skill.getID())) {
                        match = mps;
                        break;
                    }
                }
                if (match == null || match.skillLevel <= 0) {
                    continue;
                }
                final GDCharSkill cs = new GDCharSkill(match.skill.getSkillID(), match.skillLevel);
                if (skill.getAutoCastController() != null) {
                    cs.setAutoCastController(skill.getAutoCastController());
                }
                if (skill.getAutoCastSkill() != null) {
                    cs.setAutoCastSkill(skill.getAutoCastSkill());
                }
                newList.add(cs);
            }
        }
        for (final GDCharMasteryImagePane.Skill mps2 : list) {
            if (mps2.skillLevel == 0) {
                continue;
            }
            boolean found = false;
            for (final GDCharSkill skill2 : newList) {
                if (mps2.skill.getSkillID().equals(skill2.getID())) {
                    found = true;
                    break;
                }
            }
            if (found) {
                continue;
            }
            final GDCharSkill cs = new GDCharSkill(mps2.skill.getSkillID(), mps2.skillLevel);
            newList.add(cs);
        }
        this.charSkills = newList;
        this.changed = true;
    }

    public void setMasteriesAllowed(final int num) {
        this.masteriesAllowed = num;
    }

    public int refundMastery(final String masteryID) {
        if (masteryID == null) {
            return 0;
        }
        final DBSkillTree tree = DBSkillTree.getBySkillID(masteryID);
        if (tree == null) {
            return 0;
        }
        int points = 0;
        final Iterator<GDCharSkill> itSkill = this.charSkills.iterator();
        while (itSkill.hasNext()) {
            final GDCharSkill skill = itSkill.next();
            if (tree.getSkillIDList().contains(skill.getID())) {
                points += skill.getSkillLevel();
                itSkill.remove();
            }
        }
        return points;
    }

    public void read() throws IOException {
        int val = 0;
        final GDReader.Block block = new GDReader.Block();
        val = GDReader.readBlockStart(block);
        if (val != 8) {
            throw new FileVersionException(GDMsgFormatter.getString(GDMsgFormatter.rbMsg, "ERR_UNSUPPORTED_VERSION"));
        }
        this.version = GDReader.readEncInt(true);
        if (this.version != 5 && this.version != 6) {
            throw new FileVersionException(GDMsgFormatter.getString(GDMsgFormatter.rbMsg, "ERR_UNSUPPORTED_VERSION"));
        }
        this.charSkills.clear();
        val = GDReader.readEncInt(true);
        for (int i = 0; i < val; ++i) {
            final GDCharSkill skill = new GDCharSkill();
            skill.read();
            this.charSkills.add(skill);
        }
        this.masteriesAllowed = GDReader.readEncInt(true);
        this.skillReclamationPointsUsed = GDReader.readEncInt(true);
        this.devotionReclamationPointsUsed = GDReader.readEncInt(true);
        this.itemSkills.clear();
        val = GDReader.readEncInt(true);
        for (int i = 0; i < val; ++i) {
            final GDCharItemSkill skill2 = new GDCharItemSkill();
            skill2.read();
            this.itemSkills.add(skill2);
        }
        if (this.version >= 6) {
            this.subSkills.clear();
            val = GDReader.readEncInt(true);
            for (int i = 0; i < val; ++i) {
                final GDCharSubSkill skill3 = new GDCharSubSkill();
                skill3.read();
                this.subSkills.add(skill3);
            }
        }
        GDReader.readBlockEnd(block);
        this.changed = false;
    }

    public void write() throws IOException {
        final GDReader.Block block = new GDReader.Block();
        GDWriter.writeBlockStart(block, 8);
        GDWriter.writeInt(this.version);
        int val = this.charSkills.size();
        GDWriter.writeInt(val);
        for (final GDCharSkill skill : this.charSkills) {
            if (skill != null) {
                skill.write();
            }
        }
        GDWriter.writeInt(this.masteriesAllowed);
        GDWriter.writeInt(this.skillReclamationPointsUsed);
        GDWriter.writeInt(this.devotionReclamationPointsUsed);
        val = this.itemSkills.size();
        GDWriter.writeInt(val);
        for (final GDCharItemSkill skill2 : this.itemSkills) {
            if (skill2 != null) {
                skill2.write();
            }
        }
        if (this.version >= 6) {
            val = this.subSkills.size();
            GDWriter.writeInt(val);
            for (final GDCharSubSkill skill3 : this.subSkills) {
                if (skill3 != null) {
                    skill3.write();
                }
            }
        }
        GDWriter.writeBlockEnd(block);
        this.changed = false;
    }

    public int getByteSize() {
        int size = 0;
        size += 4;
        size += 4;
        size += 4;
        size += 4;
        for (final GDCharSkill skill : this.charSkills) {
            if (skill != null) {
                size += skill.getByteSize();
            }
        }
        size += 4;
        size += 4;
        size += 4;
        size += 4;
        for (final GDCharItemSkill skill2 : this.itemSkills) {
            if (skill2 != null) {
                size += skill2.getByteSize();
            }
        }
        if (this.version >= 6) {
            size += 4;
            for (final GDCharSubSkill skill3 : this.subSkills) {
                if (skill3 != null) {
                    size += skill3.getByteSize();
                }
            }
        }
        size += 4;
        return size;
    }
}
